package com.sz.common.pay.pingan.core.client;

import com.sz.common.pay.common.PayLogger;
import com.sz.common.pay.pingan.constant.Constant;
import com.sz.common.pay.pingan.exception.NoAvailableConnectException;
import com.sz.common.pay.pingan.exception.PayCommonException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;

/**
 * Function: 发送报文，并接收银行返回 <br>
 * Author: siqishangshu <br>
 * Date: 2017-10-31 10:47:00
 */
public class PAClient {

    public static final int FROM = 30;
    public static final int TO = 40;
    private static int NET_HEAD_LEN = 222;
    private static PayLogger payLogger = PayLogger.getLogger(PAClient.class);

    /**
     *
     * @param tranMessage
     * @param retKeyDict
     * @throws NoAvailableConnectException
     */
    public static void doSend(String sequence, String tranMessage, HashMap retKeyDict) throws NoAvailableConnectException, PayCommonException {
        Socket s = null;
        OutputStream os = null;
        InputStream is = null;
        Connection connection = null;
        try {
            connection = ConnectionPoolFactory.getConnection();
            //更新key的时间延长其生命周期。
            s = new Socket(connection.getHost(), connection.getPort());
            s.setSendBufferSize(Constant.BUFFER_SIZE);
            s.setTcpNoDelay(true);
            s.setSoTimeout(Constant.TIMEOUT);
            s.setKeepAlive(true);
            os = s.getOutputStream();
            is = s.getInputStream();
            os.write(tranMessage.getBytes(Constant.CHARSET_GBK));
            os.flush();

            payLogger.info(sequence, "--------------请求报文已发送, 等待银行响应....-----------------");

            //先读取通讯头报文222字节
            int netHeader = NET_HEAD_LEN;
            byte[] netHeaderBytes = new byte[netHeader];
            int netHeaderReadCount = 0;
            while (netHeaderReadCount < netHeader) {
                netHeaderReadCount += is.read(netHeaderBytes, netHeaderReadCount, netHeader - netHeaderReadCount);
            }

            //分析通讯报文头，得到业务报文头+业务报文体的长度 30-40字节
            byte[] bizBytes = Arrays.copyOfRange(netHeaderBytes, FROM, TO);
            int bizLen = Integer.parseInt(new String(bizBytes, Constant.CHARSET_GBK));

            byte[] bizBodyByte = new byte[bizLen];
            int bizBodyByteReadCount = 0;
            while (bizBodyByteReadCount < bizLen) {
                bizBodyByteReadCount += is.read(bizBodyByte, bizBodyByteReadCount, bizLen - bizBodyByteReadCount);
            }

            //拼装接收到的银行返回报文
            String recvMessage = new String(netHeaderBytes, Constant.CHARSET_GBK) + new String(bizBodyByte, Constant.CHARSET_GBK);

            //修复使用spilt方法时的数组越界错误
            recvMessage = recvMessage + '\0';

            retKeyDict.put(Constant.RECIVE_MESSAGE, recvMessage);

        } catch (SocketException e) {
            payLogger.error(sequence,e.getMessage());
            throw new PayCommonException("Socket Exception");
        } catch (UnknownHostException e) {
            payLogger.error(sequence,connection.getHost()+e.getMessage());
            throw new PayCommonException("Unknown Host Exception");
        } catch (UnsupportedEncodingException e) {
            payLogger.error(sequence,e.getMessage());
            throw new PayCommonException("Encoding Exception");
        } catch (IOException e) {
            payLogger.error(sequence,e.getMessage());
            e.printStackTrace();
            throw new PayCommonException("IO Exception");
        } finally {
            try {
                if (connection != null) {
                    connection.unlock();
                }
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
                if (s != null) {
                    s.close();
                }
            } catch (IOException e) {
                payLogger.error(sequence,e.getMessage());
                throw new PayCommonException("IO Exception");
            }
        }


    }

}
